package de.dqi.pong.graphics;

import static de.dqi.pong.graphics.Colour.WHITE;

import java.awt.image.BufferedImage;

import de.dqi.pong.engine.InitializationNotification;
import de.dqi.pong.engine.TickNotification;


/**
 * 	
 * <hr><dl><dt>
 * Summary: </dt><br><dd>
 *  Renders the Board, including the Bats and the Ball, to an image.
 * </dd><br><dt>
 * Author: </dt><br><dd>
 *  Vincent
 * </dd></dl>
 */
public class Render {
	
	private Display			display;
	private String			nameLeft		= "Player 1";
	private String			nameRight		= "Player 2";
	private int				pixHeight		= 700;
	private int				pixWidth		= 850;
	private double			fieldWidth		= 65;
	private double			fieldHeight		= 60;
	private double			marginWidth		= 1 / 10;
	private double			marginHeight	= 1 / 50;
	private double			batHeight		= 3;
	private double			ballRadius		= 0.5;
	private Point			origin;
	private Dimension		fieldMap;
	
	private BufferedImage	frame;
	private int[]			framebuffer;
	
	private Colour			colour			= WHITE;
	
	
	/**
	 * 
	 * <hr>
	 * @param source
	 */
	public Render() {
		
		display = new Display(this);
		
		framebuffer = new int[pixWidth * pixHeight];
	}
	
	public void setPlayerNames(String pL, String pR) {
		nameLeft = pL;
		nameRight = pR;
	}
	
	public void initialize(InitializationNotification init) {
		fieldWidth = init.fieldWidth;
		fieldHeight = init.fieldHeight;
		batHeight = init.batSpan * 2;
		ballRadius = init.ballRadius;
	}
	
	public Display getDisplay() {
		return display;
	}
	
	/**
	 * WIP: Draw score
	 * <hr>
	 * 
	 * <hr>
	 */
	public void drawFrame(TickNotification tick) {
		
		colour = Colour.BLACK;
		drawRect(0, 0, pixWidth, pixHeight);
		
		colour = Colour.WHITE;
		Point ballPos = map(tick.posBallX, tick.posBallY);
		drawCircle(ballPos.x, ballPos.y, convert(ballRadius, 0).width);
		
		drawRect(100, 49, 650, 1);
		drawRect(749, 49, 1, 600);
		drawRect(100, 649, 650, 1);
		drawRect(100, 49, 1, 600);
		
		Dimension batSize = convert(1, batHeight);
		Point batLeftPos = map(-1, tick.posBatLeft - batHeight / 2);
		drawRect(batLeftPos.x, batLeftPos.y, batSize.width, batSize.height);
		Point batRightPos = map(fieldWidth, tick.posBatRight - batHeight / 2);
		drawRect(batRightPos.x, batRightPos.y, batSize.width, batSize.height);
		
		drawString(-2, pixHeight - 8, nameLeft, false, 2);
		drawString(pixWidth + 2, pixHeight - 8, nameRight, true, 2);
		
		display.drawFrame(framebuffer);
	}
	
	
//	private void recalculateCoordinates() {
//		System.out.println("recalc...");
//		System.out.println(Double.toString(fieldWidth) + "|" + Double.toString(fieldHeight) + " Field");
//		System.out.println(Integer.toString(pixWidth) + "|" + Integer.toString(pixHeight) + " Pixels");
//		double pixRatio = (double) pixWidth / (double) pixHeight;
//		double fieldRatio = fieldWidth + fieldWidth * marginWidth / fieldHeight + fieldHeight * marginHeight;
//		int xZero;
//		int yZero;
//		if (pixRatio > fieldRatio) {
//			xZero = (int) (pixWidth - (pixHeight * fieldWidth / fieldHeight)) / 2;
//			yZero = (int) (pixHeight * (marginHeight / (1 + 2 * marginHeight)));
//			
//			origin = new Point(xZero, yZero);
//		} else {
//			xZero = (int) (pixWidth * (marginWidth / (1 + 2 * marginWidth)));
//			yZero = (int) (pixHeight - (pixWidth * fieldHeight / fieldWidth)) / 2;
//		}
//		fieldMap = new Dimension(pixWidth - 2 * xZero, pixHeight - 2 * yZero);
//		origin = new Point(xZero, yZero + fieldMap.height);
//		System.out.println(xZero);
//		System.out.println(yZero);
//		System.out.println(Integer.toString(fieldMap.width) + "|" + Integer.toString(fieldMap.height) + " fieldMap");
//		System.out.println(Integer.toString(origin.x) + "|" + Integer.toString(origin.y) + " origin");
//	}
	
	private void drawString(int x, int y, String text, boolean leftAlign, int size) {
		//TODO Actually draw any Strings.
	}
	
	private void drawChar(int x, int y, char letter, int size) {
		//TODO Make drawing Characters possible.
	}
	
	private void drawLine(int xStart, int yStart, int xEnd, int yEnd) {
		//TODO Is this even needed?
	}
	
	private void drawRect(int x, int y, int width, int height) {
		int dX = Integer.signum(width);
		int dY = Integer.signum(height);
		
		width = x + width;
		height = y + height;
		
		if (x < 0) {
			x = 0;
		}
		else if (x >= pixWidth) {
			x = pixWidth - 1;
		}
		if (y < 0) {
			y = 0;
		}
		else if (y >= pixHeight) {
			y = pixHeight - 1;
		}
		
		if (width < 0) {
			width = 0;
		}
		else if (width >= pixWidth) {
			width = pixWidth - 1;
		}
		if (height < 0) {
			height = 0;
		}
		else if (height >= pixHeight) {
			height = pixHeight - 1;
		}
		
		for (int ix = x; ix != width; ix += dX) {
			for (int iy = y; iy != height; iy += dY) {
				setPixel(ix, iy);
			}
		}
	}
	
	private void drawCircle(int x, int y, int r) {
		//WIP Make drawCircle() actually draw a Circle, rather than a Square.
		drawRect(x - r, y - r, 2 * r, 2 * r);
	}
	
	private void setPixel(int x, int y) {
		framebuffer[y * pixWidth + x] = (colour.r << 16) | colour.g << 8 | colour.b;
	}
	
	public Point map(double x, double y) {
		int convX = (int) (x * 10 + 100);
		int convY = (int) (y * 10 + 50);
		return new Point(convX, convY);
	}
	
	public Dimension convert(double width, double height) {
		int convWidth = (int) (width * 10);
		int convHeight = (int) (height * 10);
		return new Dimension(convWidth, convHeight);
	}
	
}
